package com.group.transaction.util;

import com.group.transaction.enums.DateTimeEnum;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;

/**
 * 时间处理工具类
 *
 * @author YunXing Pang
 * @date 2019/06/17
 */
public class DateTimeUtil {

    private DateTimeUtil() {
        super();
    }

    /**
     * 部分时间字符串转换时间对象
     *
     * @param dateTimeString 时间字符串
     * @return 时间对象
     */
    public static Date dateTimeStringConverter(String dateTimeString) {
        if (StringUtil.isEmpty(dateTimeString)) {
            return null;
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM_SS_SSS.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM_SS_SSS.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM_SS.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM_SS.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_YYYY_MM_DD.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_YYYY_MM_DD.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_YYYY_MM.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_YYYY_MM.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.SLASH_YYYY_MM_DD_HH_MM_SS_SSS.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.SLASH_YYYY_MM_DD_HH_MM_SS_SSS.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.SLASH_YYYY_MM_DD_HH_MM_SS.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.SLASH_YYYY_MM_DD_HH_MM_SS.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.SLASH_YYYY_MM_DD_HH_MM.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.SLASH_YYYY_MM_DD_HH_MM.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.SLASH_YYYY_MM_DD.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.SLASH_YYYY_MM_DD.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.SLASH_YYYY_MM.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.SLASH_YYYY_MM.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_HH_MM_SS_SSS.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_HH_MM_SS_SSS.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_HH_MM_SS.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_HH_MM_SS.getFormat());
        }
        if (dateTimeString.matches(DateTimeEnum.NORMAL_HH_MM.getRegular())) {
            return dateTimeStringToDateTime(dateTimeString, DateTimeEnum.NORMAL_HH_MM.getFormat());
        }
        return null;
    }

    /**
     * 获取LocalDateTime对象
     *
     * @param dateTime 时间对象
     * @return LocalDateTime对象
     */
    public static LocalDateTime getLocalDateTime(Date dateTime) {
        if (Objects.isNull(dateTime)) {
            return LocalDateTime.now(ZoneId.systemDefault());
        }
        return LocalDateTime.ofInstant(dateTime.toInstant(), ZoneId.systemDefault());
    }

    /**
     * 获取当前时间
     *
     * @return 当前时间字符串
     */
    public static Date getNowDateTime() {
        return Date.from(getLocalDateTime(null).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间的字符串
     *
     * @return 当前时间字符串
     */
    public static String getNowDateTimeString(String format) {
        if (StringUtil.isEmpty(format)) {
            return getLocalDateTime(null).format(DateTimeFormatter.ofPattern(DateTimeEnum.NORMAL_YYYY_MM_DD_HH_MM_SS.getFormat()));
        }
        return getLocalDateTime(null).format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 时间字符串转换为时间对象
     *
     * @param dateTimeString 时间字符串
     * @return 时间对象
     */
    public static Date dateTimeStringToDateTime(String dateTimeString, String dateTimeFormat) {
        if (StringUtil.isEmpty(dateTimeString) || StringUtil.isEmpty(dateTimeFormat)) {
            return null;
        }
        boolean isDate = dateTimeFormat.contains("y") || dateTimeFormat.contains("M") || dateTimeFormat.contains("d");
        boolean isTime = dateTimeFormat.contains("H") || dateTimeFormat.contains("h") || dateTimeFormat.contains("m") || dateTimeFormat.contains("s") || dateTimeFormat.contains("S");
        if (isDate && isTime) {
            return Date.from(LocalDateTime.parse(dateTimeString, DateTimeFormatter.ofPattern(dateTimeFormat)).atZone(ZoneId.systemDefault()).toInstant());
        } else if (isDate) {
            return Date.from(LocalDateTime.of(LocalDate.parse(dateTimeString, DateTimeFormatter.ofPattern(dateTimeFormat)), LocalTime.of(0, 0, 0)).atZone(ZoneId.systemDefault()).toInstant());
        } else {
            return Date.from(LocalDateTime.of(LocalDate.now(ZoneId.systemDefault()), LocalTime.parse(dateTimeString, DateTimeFormatter.ofPattern(dateTimeFormat))).atZone(ZoneId.systemDefault()).toInstant());
        }
    }

    /**
     * 时间对象转换为时间字符串
     *
     * @param dateTime       时间对象
     * @param dateTimeFormat 时间字符串格式
     * @return 时间字符串
     */
    public static String dateTimeToDateTimeString(Date dateTime, String dateTimeFormat) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (StringUtil.isEmpty(dateTimeFormat)) {
            return localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME).replace("T", " ");
        }
        return localDateTime.format(DateTimeFormatter.ofPattern(dateTimeFormat));
    }

    /**
     * 两个时间相差多少年
     *
     * @param dateTimeOne 第一个时间
     * @param dateTimeTwo 第二个时间
     * @return 相差的年份数量
     */
    public static long dateTimesDifferenceByYear(Date dateTimeOne, Date dateTimeTwo) {
        return Period.between(getLocalDateTime(dateTimeOne).toLocalDate(), getLocalDateTime(dateTimeTwo).toLocalDate()).getYears();
    }

    /**
     * 两个时间相差多少月
     *
     * @param dateTimeOne 第一个时间
     * @param dateTimeTwo 第二个时间
     * @return 相差的月份数量
     */
    public static long dateTimesDifferenceByMonth(Date dateTimeOne, Date dateTimeTwo) {
        return Period.between(getLocalDateTime(dateTimeOne).toLocalDate(), getLocalDateTime(dateTimeTwo).toLocalDate()).toTotalMonths();
    }

    /**
     * 两个时间相差多少天
     *
     * @param dateTimeOne 第一个时间
     * @param dateTimeTwo 第二个时间
     * @return 相差的天数
     */
    public static long dateTimesDifferenceByDay(Date dateTimeOne, Date dateTimeTwo) {
        return Duration.between(getLocalDateTime(dateTimeOne), getLocalDateTime(dateTimeTwo)).toDays();
    }

    /**
     * 两个时间相差多少小时
     *
     * @param dateTimeOne 第一个时间
     * @param dateTimeTwo 第二个时间
     * @return 相差的小时数
     */
    public static long dateTimesDifferenceByHour(Date dateTimeOne, Date dateTimeTwo) {
        return Duration.between(getLocalDateTime(dateTimeOne), getLocalDateTime(dateTimeTwo)).toHours();
    }

    /**
     * 两个时间相差多少分钟
     *
     * @param dateTimeOne 第一个时间
     * @param dateTimeTwo 第二个时间
     * @return 相差的分钟数
     */
    public static long dateTimesDifferenceByMinute(Date dateTimeOne, Date dateTimeTwo) {
        return Duration.between(getLocalDateTime(dateTimeOne), getLocalDateTime(dateTimeTwo)).toMinutes();
    }

    /**
     * 两个时间相差多少秒
     *
     * @param dateTimeOne 第一个时间
     * @param dateTimeTwo 第二个时间
     * @return 相差的秒数
     */
    public static long dateTimesDifferenceBySecond(Date dateTimeOne, Date dateTimeTwo) {
        return Duration.between(getLocalDateTime(dateTimeOne), getLocalDateTime(dateTimeTwo)).getSeconds();
    }

    /**
     * 获取当前时间增减秒数后的时间
     *
     * @param dateTime 当前时间对象
     * @param seconds  秒数
     * @return 当前时间增减秒数后的时间对象
     */
    public static Date dateTimeAddOrSubtractSeconds(Date dateTime, int seconds) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (seconds > 0) {
            return Date.from(localDateTime.plusSeconds(seconds).atZone(ZoneId.systemDefault()).toInstant());
        }
        return Date.from(localDateTime.minusSeconds(-seconds).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间增减分数后的时间
     *
     * @param dateTime 当前时间对象
     * @param minutes  分数
     * @return 当前时间增减分数后的时间对象
     */
    public static Date dateTimeAddOrSubtractMinutes(Date dateTime, int minutes) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (minutes > 0) {
            return Date.from(localDateTime.plusMinutes(minutes).atZone(ZoneId.systemDefault()).toInstant());
        }
        return Date.from(localDateTime.minusMinutes(-minutes).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间增减小时数后的时间
     *
     * @param dateTime 当前时间对象
     * @param hours    小时数
     * @return 当前时间增减小时数后的时间对象
     */
    public static Date dateTimeAddOrSubtractHours(Date dateTime, int hours) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (hours > 0) {
            return Date.from(localDateTime.plusHours(hours).atZone(ZoneId.systemDefault()).toInstant());
        }
        return Date.from(localDateTime.minusHours(-hours).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前全年时间增减天数后的时间
     *
     * @param dateTime 当前时间对象
     * @param days     天数
     * @return 当前全年时间增减天数后的时间对象
     */
    public static Date dateTimeAddOrSubtractDays(Date dateTime, int days) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (days > 0) {
            return Date.from(localDateTime.plusDays(days).atZone(ZoneId.systemDefault()).toInstant());
        }
        return Date.from(localDateTime.minusDays(-days).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间增减月数后的时间
     *
     * @param dateTime 当前时间对象
     * @param months   月数
     * @return 当前时间增减月数后的时间对象
     */
    public static Date dateTimeAddOrSubtractMonths(Date dateTime, int months) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (months > 0) {
            return Date.from(localDateTime.plusMonths(months).atZone(ZoneId.systemDefault()).toInstant());
        }
        return Date.from(localDateTime.minusMonths(-months).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间增减年数后的时间
     *
     * @param dateTime 当前时间对象
     * @param years    年数
     * @return 当前时间增减年数后的时间对象
     */
    public static Date dateTimeAddOrSubtractYears(Date dateTime, int years) {
        LocalDateTime localDateTime = getLocalDateTime(dateTime);
        if (years > 0) {
            return Date.from(localDateTime.plusYears(years).atZone(ZoneId.systemDefault()).toInstant());
        }
        return Date.from(localDateTime.minusYears(-years).atZone(ZoneId.systemDefault()).toInstant());
    }

    /**
     * 获取当前时间的年份
     *
     * @param dateTime 当前时间
     * @return 当前时间的年份
     */
    public static int getYear(Date dateTime) {
        return getLocalDateTime(dateTime).getYear();
    }

    /**
     * 获取当前时间的月份
     *
     * @param dateTime 当前时间
     * @return 当前时间的月份
     */
    public static int getMonth(Date dateTime) {
        return getLocalDateTime(dateTime).getMonthValue();
    }

    /**
     * 获取当前时间在某年里对应的天数
     *
     * @param dateTime 当前时间
     * @return 当前时间在某年里对应的天数
     */
    public static int getDayByYear(Date dateTime) {
        return getLocalDateTime(dateTime).getDayOfYear();
    }

    /**
     * 获取当前时间在某月里对应的天数
     *
     * @param dateTime 当前时间
     * @return 当前时间在某月里对应的天数
     */
    public static int getDayByMonth(Date dateTime) {
        return getLocalDateTime(dateTime).getDayOfMonth();
    }

    /**
     * 获取当前时间在某星期里对应的天数
     *
     * @param dateTime 当前时间
     * @return 当前时间在某星期里对应的天数
     */
    public static int getDayByWeek(Date dateTime) {
        return getLocalDateTime(dateTime).getDayOfWeek().getValue();
    }

    /**
     * 获取当前时间的小时
     *
     * @param dateTime 当前时间
     * @return 当前时间的小时
     */
    public static int getHour(Date dateTime) {
        return getLocalDateTime(dateTime).getHour();
    }

    /**
     * 获取当前时间的分钟
     *
     * @param dateTime 当前时间
     * @return 当前时间的分钟
     */
    public static int getMinute(Date dateTime) {
        return getLocalDateTime(dateTime).getMinute();
    }

    /**
     * 获取当前时间的秒
     *
     * @param dateTime 当前时间
     * @return 当前时间的秒
     */
    public static int getSecond(Date dateTime) {
        return getLocalDateTime(dateTime).getSecond();
    }
}
